import gugga.sequence.IPreconditionsManager;
import gugga.sequence.PreconditionsManager;
import gugga.sequence.FictiveTask;
import gugga.common.EventDescriptor;

import guggaLibTests.support.TaskExecutionEvaluator;

import test_framework.test.unit.TestCase;

/**
 * @author vladimir
 */
class guggaLibTests.PreconditionsManagerTest
		extends TestCase
{
	private var preconditionsMet:Boolean;
	
	public function PreconditionsManagerTest()
	{
		super();
		this.preconditionsMet = false;
	}
	
	public function testConstructor()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		assertNotNull(
				"preconditionsManager should not be null after creation", 
				preconditionsManager);
		assertNotUndefined(
				"preconditionsManager should not be undefined after creation", 
				preconditionsManager);
		assertEquals(
				"preconditionsManager.isAccepting() should equals initialIsAccepting after creation", 
				preconditionsManager.isAccepting(), 
				initialIsAccepting);
	}
	
	public function testAccepting()
	{
		var initialIsAccepting:Boolean = false;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		assertEquals(
				"preconditionsManager.isAccepting() should equals initialIsAccepting",
				preconditionsManager.isAccepting(), 
				initialIsAccepting);
		assertEquals(
				"preconditionsManager.Accepting should equals initialIsAccepting",
				preconditionsManager.Accepting, 
				initialIsAccepting);
	}
	
	public function testAddContainsRemove()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		assertTrue(
				"preconditionsManager should contain precondition1", 
				preconditionsManager.contains(precondition1));
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		assertTrue(
				"preconditionsManager should contain precondition2", 
				preconditionsManager.contains(precondition2));
				
		assertTrue(
				"preconditionsManager should contain precondition1 and precondition2", 
				preconditionsManager.contains(precondition1) && preconditionsManager.contains(precondition2));
		
		preconditionsManager.remove(precondition1);
		assertFalse(
				"preconditionsManager should not contain precondition1 - it was removed", 
				preconditionsManager.contains(precondition1));
		
		assertTrue(
				"preconditionsManager should contain precondition2 (only precondition1 was removed)", 
				preconditionsManager.contains(precondition2));
	}
	
	public function testRemoveByEventSource()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		assertTrue(
				"preconditionsManager should contain precondition1 and precondition2", 
				preconditionsManager.contains(precondition1) && preconditionsManager.contains(precondition2));
		
		preconditionsManager.removeByEventSource(eventSource1);
		
		assertFalse(
				"preconditionsManager should not contain precondition1 - it was removed by its EventSource", 
				preconditionsManager.contains(precondition1));
		
		assertTrue(
				"preconditionsManager should contain precondition2 (only precondition1 was removed)", 
				preconditionsManager.contains(precondition2));
	}
	
	public function testReplace()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		preconditionsManager.add(precondition);
		
		assertTrue(
				"preconditionsManager should contain precondition", 
				preconditionsManager.contains(precondition));
		
		var eventSourceNew:FictiveTask = new FictiveTask();
		var preconditionNew:EventDescriptor = new EventDescriptor(
				eventSourceNew, 
				"start");
		preconditionsManager.replace(precondition, preconditionNew);
		
		assertFalse(
				"preconditionsManager should not contain precondition - it was replaced", 
				preconditionsManager.contains(precondition));
		assertTrue(
				"preconditionsManager should contain preconditionNew after replace", 
				preconditionsManager.contains(preconditionNew));
	}
	
	public function testReplaceEventSourceOnSinglePrecondition()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		preconditionsManager.add(precondition);
		
		var eventSourceNew:FictiveTask = new FictiveTask();
		preconditionsManager.replaceEventSource(eventSource, eventSourceNew);
		
		eventSource.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition's EventSource was replaced",
				preconditionsManager.PreconditionsMet);
		
		eventSourceNew.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because the new EventSource was used to dispatch the event",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testReplaceEventSourceOnMultiplePreconditions()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		var eventSourceNew:FictiveTask = new FictiveTask();
		preconditionsManager.replaceEventSource(eventSource1, eventSourceNew);
		
		eventSource1.start();
		eventSource2.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition1's EventSource was replaced",
				preconditionsManager.PreconditionsMet);
		
		eventSourceNew.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because the new EventSource was used to dispatch the events for precondition1, and precondition2 is already met",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testIgnoreAcceptAll()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		preconditionsManager.ignoreAll();
		eventSource1.start();
		eventSource2.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because all preconditions are ignored",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.acceptAll();
		eventSource1.start();
		eventSource2.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because all preconditions are now accepted",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testIgnoreAcceptOnSinglePrecondition()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		preconditionsManager.add(precondition);
		
		preconditionsManager.ignore(precondition);
		eventSource.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition is ignored",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.accept(precondition);
		eventSource.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because precondition now is accepted",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testIgnoreAcceptOnMultiplePreconditions()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		preconditionsManager.ignore(precondition1);
		eventSource1.start();
		eventSource2.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition1 is ignored",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.accept(precondition1);
		eventSource1.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because precondition1 now is accepted and precondition2 is already met",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testIgnoreAcceptEventSourceOnSinglePrecondition()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		preconditionsManager.add(precondition);
		
		preconditionsManager.ignoreEventSource(eventSource);
		eventSource.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition's EventSource is ignored",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.acceptEventSource(eventSource);
		eventSource.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because precondition's EventSource now is accepted",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testIgnoreAcceptEventSourceOnMultiplePreconditions()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		preconditionsManager.ignoreEventSource(eventSource1);
		eventSource1.start();
		eventSource2.start();
		assertFalse(
				"preconditionsManager.mPreconditions checklist should not be met, because precondition1's EventSource is ignored",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.acceptEventSource(eventSource1);
		eventSource1.start();
		assertTrue(
				"preconditionsManager.mPreconditions checklist should be met, because precondition1's EventSource now is accepted and precondition2 is already met",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testPreconditionsMetAfterCreationNoPreconditionsSpecified()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		preconditionsManager.addEventListener(
				"preconditionsMet", 
				onPreconditionsMet);
		
		// after creation preconditionsManager.mPreconditions checklist should 
		// be empty, therefore preconditions should be met:
		assertTrue(
				"aPreconditionsManager.mPreconditions checklist should be met after creation",
				preconditionsManager.PreconditionsMet);
				
		assertEquals(
				"aPreconditionsManager.PreconditionsMet should equals aPreconditionsManager.getPreconditionsMet()", 
				preconditionsManager.PreconditionsMet, 
				preconditionsManager.getPreconditionsMet());
		
		assertFalse(
				"preconditionsManager should not raise the preconditionsMet event, when not started within a PreconditionsTask", 
				this.preconditionsMet);
	}
	
	public function testPreconditionsMetAfterSingleAdd()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource:FictiveTask = new FictiveTask();
		var precondition:EventDescriptor = new EventDescriptor(
				eventSource, 
				"start");
		
		preconditionsManager.add(precondition);
		assertFalse(
				"aPreconditionsManager.mPreconditions checklist should not be met after adding a new precondition",
				preconditionsManager.PreconditionsMet);
		
		// meet precondition and assert that preconditions checklist is met:
		eventSource.start();
		assertTrue(
				"aPreconditionsManager.PreconditionsMet should be true",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testPreconditionsMetAfterMultipleAdd()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
			
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		assertFalse(
				"aPreconditionsManager.mPreconditions checklist should not be met after adding two new preconditions",
				preconditionsManager.PreconditionsMet);
		
		// meet precondition1 and assert that preconditions checklist is still 
		// not met(precondition2 is not met yet):
		eventSource1.start("test");
		assertFalse(
				"aPreconditionsManager.PreconditionsMet should be false (there is still precondition that is not met)",
				preconditionsManager.PreconditionsMet);
		
		// meet precondition2 and assert that all preconditions in the 
		// checklist are met:
		eventSource2.start("test");
		assertTrue(
				"aPreconditionsManager.PreconditionsMet should be true - all preconditions are met",
				preconditionsManager.PreconditionsMet);
	}
	
	public function testReset()
	{
		var initialIsAccepting:Boolean = true;
		var preconditionsManager:PreconditionsManager 
			= new PreconditionsManager(initialIsAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		eventSource1.start();
		eventSource2.start();
		assertTrue(
				"preconditionsManager.PreconditionsMet should be true - all preconditions are met",
				preconditionsManager.PreconditionsMet);
		
		preconditionsManager.reset();
		
		assertTrue(
				"preconditionsManager should still have precondition1 after reset", 
				preconditionsManager.contains(precondition1));
				
		assertTrue(
				"preconditionsManager should still have precondition2 after reset", 
				preconditionsManager.contains(precondition2));
		
		assertFalse(
				"preconditionsManager.PreconditionsMet should be not true - all preconditions are reset to listen again",
				preconditionsManager.PreconditionsMet);
		
		eventSource1.start();
		eventSource2.start();
		assertTrue(
				"preconditionsManager.PreconditionsMet should be true - all preconditions are met after reset",
				preconditionsManager.PreconditionsMet);
	}
	
	private function onPreconditionsMet()
	{
		this.preconditionsMet = true;
	}
	
	private function reset()
	{
		this.preconditionsMet = false;
	}
}